package edu.ucla.cs.cs144;

import java.io.IOException;
import java.io.StringReader;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONArray;
import org.json.JSONObject;

import org.xml.sax.InputSource;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ErrorHandler;

import edu.ucla.cs.cs144.Tag;

public class ItemServlet extends HttpServlet implements Servlet {
       
    public ItemServlet() {}
    
    static final class Attribute {
	static final String ITEMID = "ItemID";
	static final String RATING = "Rating";	
	static final String USERID = "UserID";
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        HttpSession session = request.getSession(true);		// Don't know what to do with this yet
		
		// get id from request and obtain XML data for that id
		String id = request.getParameter("id");
		String result = "<root>" + AuctionSearchClient.getXMLDataForItemId(id) + "</root>";
		
		// parse XML result
		Document doc = null;
		try {
			DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			InputSource inStream = new InputSource();
			inStream.setCharacterStream(new StringReader(result));
            		doc = builder.parse(inStream);
		}
		catch (IOException e) {
		    e.printStackTrace();
		    System.exit(3);
		}
		catch (SAXException e) {
		    e.printStackTrace();
		    System.exit(3);
		}
		catch (ParserConfigurationException e) {
		    e.printStackTrace();
		    System.exit(3);
		}
		
		// variables to be used during parsing
		String categories = "";
		int totalBidsFound = 0;
					
		JSONObject jsonBids = new JSONObject();
		JSONObject json = new JSONObject();
		Node item = null;
		Element items = doc.getDocumentElement();
			
		// Get the first Item node if it exists
		if (items.getElementsByTagName(Tag.ITEM).getLength() != 0)
		{
			item = items.getElementsByTagName(Tag.ITEM).item(0);
			
			// get item ID
			json.put(encode("ItemID"), encode(item.getAttributes().getNamedItem(Attribute.ITEMID).getNodeValue()));
				
			Node n = item.getFirstChild();
				
			do 
			{
				if (n.getNodeName().equals(Tag.NAME))
				{
					json.put(encode(Tag.NAME), encode(n.getFirstChild().getNodeValue()));
				}
				if (n.getNodeName().equals(Tag.CATEGORY)) 
				{
					// Parse the Categories into a single list
					do {
						if (categories.equals(""))
						{
							categories = n.getFirstChild().getNodeValue();
						}
						else
						{
							categories = categories + ", " + n.getFirstChild().getNodeValue();
						}
						n = n.getNextSibling();
					} while (n != null && n.getNodeName().equals(Tag.CATEGORY));
					
					// Rewind one Node so that when we step forward in the main loop, we don't skip a Node
					n = n.getPreviousSibling();
				} 
				else if (n.getNodeName().equals(Tag.BIDS)) 
				{
					// Parse the Bids
					NodeList n_children = n.getChildNodes();
					
					for(int i = 0; i < n_children.getLength(); i++)
					{
						Node child = n_children.item(i);
						
						String prefix = "Bid-" + Integer.toString(i);
						
						if (child.getNodeName().equals(Tag.Bids.BID))
						{
							NodeList bid_children = child.getChildNodes();
							
							JSONObject jsonBid = new JSONObject();
							
							for (int j = 0; j < bid_children.getLength(); j++)
							{
								Node bid = bid_children.item(j);
								
								if (bid.getNodeName().equals(Tag.Bids.Bid.BIDDER))
								{
									NodeList bidder_children = bid.getChildNodes();
									
									for (int k = 0; k < bidder_children.getLength(); k++)
									{
										Node bidder_child = bidder_children.item(k);
										
										if (bidder_child.getNodeName().equals(Tag.Bids.Bid.LOCATION))
										{
											jsonBid.put(Tag.Bids.Bid.LOCATION, bidder_child.getFirstChild().getNodeValue());
										}
										else if (bidder_child.getNodeName().equals(Tag.Bids.Bid.COUNTRY))
										{
											jsonBid.put(Tag.Bids.Bid.COUNTRY, bidder_child.getFirstChild().getNodeValue());
										}
									}
								
									jsonBid.put(Attribute.USERID,encode(bid.getAttributes().getNamedItem(Attribute.USERID).getNodeValue()));
									jsonBid.put(Attribute.RATING,encode(bid.getAttributes().getNamedItem(Attribute.RATING).getNodeValue()));
								}
								else if (bid.getNodeName().equals(Tag.Bids.TIME))
								{
									jsonBid.put(Tag.Bids.TIME,encode(bid.getFirstChild().getNodeValue()));
								}
								else if (bid.getNodeName().equals(Tag.Bids.AMOUNT))
								{
									jsonBid.put(Tag.Bids.AMOUNT,encode(bid.getFirstChild().getNodeValue()));
								}
							}
							
							jsonBids.put(Integer.toString(totalBidsFound), jsonBid);
							
							totalBidsFound += 1;
						}
					}
				} 
				else if (n.getNodeName().equals(Tag.SELLER)) 
				{
					// Seller Node
					json.put(encode(Tag.SELLER+"_"+Attribute.USERID), encode(n.getAttributes().getNamedItem(Attribute.USERID).getNodeValue()));
					json.put(encode(Tag.SELLER+"_"+Attribute.RATING), encode(n.getAttributes().getNamedItem(Attribute.RATING).getNodeValue()));
				} 
				else if (n.getNodeName().equals(Tag.CURRENTLY)) 
				{
					json.put(encode(Tag.CURRENTLY), encode(n.getFirstChild().getNodeValue()));
				}
				else if (n.getNodeName().equals(Tag.BUY_PRICE)) 
				{
					json.put(encode(Tag.BUY_PRICE), encode(n.getFirstChild().getNodeValue()));
				}
				else if (n.getNodeName().equals(Tag.FIRST_BID)) {
					if (n.getFirstChild() != null)
					{
						json.put(encode(Tag.FIRST_BID), encode(n.getFirstChild().getNodeValue()));
					}
				} 
				else if (n.getNodeName().equals(Tag.NUMBER_OF_BIDS)) 
				{
					json.put(encode(Tag.NUMBER_OF_BIDS), encode(n.getFirstChild().getNodeValue()));
				} 
				else if (n.getNodeName().equals(Tag.STARTED)) 
				{
					json.put(encode(Tag.STARTED), encode(n.getFirstChild().getNodeValue()));
				} 
				else if (n.getNodeName().equals(Tag.ENDS)) 
				{
					json.put(encode(Tag.ENDS), encode(n.getFirstChild().getNodeValue()));
				} 
				else if (n.getNodeName().equals(Tag.LOCATION)) 
				{
					json.put(encode(Tag.LOCATION), encode(n.getFirstChild().getNodeValue()));
				} 
				else if (n.getNodeName().equals(Tag.COUNTRY)) 
				{
					json.put(encode(Tag.COUNTRY), encode(n.getFirstChild().getNodeValue()));
				}
				else 
				{
					// Normal node with just text and no attributes
					if (n.getFirstChild() != null)
					{
						json.put(encode(Tag.DESCRIPTION), encode(n.getFirstChild().getNodeValue()));
					}
				}
			} while ((n = n.getNextSibling()) != null);
			
			json.put(encode(Tag.CATEGORY), encode(categories));
		}
		else
		{
			json.put("error", "No items with that ID found");
		}
		
		request.setAttribute("bids", jsonBids.toString());
		request.setAttribute("result", json.toString());
		request.getRequestDispatcher("/itemResult.jsp").forward(request, response);	
    }

	// Encodes a string with escape characters
	private String encode(String s) {
		
		return s.replaceAll("\"", "&quot;")
				.replaceAll("\'", "&apos;")
				.replaceAll("&", "&amp;")
				.replaceAll("<", "&lt;")
				.replaceAll(">", "&gt;");
	}
}
